Skip to content

Strip unnecessary fields in wpcom_request response#3005

Merged
epeicher merged 6 commits intotrunkfrom
stu-1524-long-api-responses-return-error-96079-characters-exceeds
Apr 9, 2026
Merged

Strip unnecessary fields in wpcom_request response#3005
epeicher merged 6 commits intotrunkfrom
stu-1524-long-api-responses-return-error-96079-characters-exceeds

Conversation

@epeicher
Copy link
Copy Markdown
Contributor

@epeicher epeicher commented Apr 8, 2026

Related issues

How AI was used in this PR

AI assisted with debugging the root cause (identifying that plan.features was 63K+ chars) and writing the compact extraction logic.

Proposed Changes

  • System prompt guidance: Add a hint instructing the agent to use _fields on wp/v2 listing endpoints (templates, posts, pages, etc.) to request only lightweight fields and exclude heavy ones like content. This is the generic solution for large responses.
  • Special case for plan.features: Add a compactResponse() function that strips plan.features (60K+ chars) from /sites/{id} responses, keeping only product_id, product_slug, product_name_short, expired, and is_free. This can't be solved via query params because the v1.1 API doesn't support sub-field filtering (e.g. fields=plan.product_slug). The function includes a clear comment explaining this is a special case, not a pattern to follow.

Testing Instructions

  • Apply these changes and run npm run cli:build. Then start studio ai by running node apps/cli/dist/cli/main.mjs ai
  • Connect to a remote WordPress.com site by pressing down arrow and then right arrow
  • Ask the agent a question that triggers wpcom_request (e.g., "What's the current name, tagline, and active theme of this site?")
  • Verify the response succeeds without exceeding the MCP output limit, i.e. you don't see the error: Error: result (96,907 characters) exceeds maximum allowed tokens. Output has been saved to…
  • Ask the agent to modify a block theme template on a remote site → verify it uses wp/v2 endpoints
  • Ask the agent for design changes on a free WP.com site → verify it explains the paid plan limitation
Before After
CleanShot 2026-04-08 at 13 17 00@2x CleanShot 2026-04-08 at 13 14 41@2x

Pre-merge Checklist

  • Have you checked for TypeScript, React or other console errors?

@epeicher epeicher self-assigned this Apr 8, 2026
@youknowriad youknowriad force-pushed the remote-site-wpcom-mcp branch from ff2e207 to a3c7f6a Compare April 8, 2026 09:43
Base automatically changed from remote-site-wpcom-mcp to trunk April 8, 2026 10:19
The WP.com /sites/{id} endpoint returns a plan object whose features
sub-field alone is 60K+ characters, pushing the total response past
Claude Code's ~100K character MCP tool result limit. The agent only
needs product_slug, is_free, and expired to gate features, since the
system prompt hardcodes what each plan tier can and can't do. Strip
plan.features and keep only essential plan properties.
@epeicher epeicher force-pushed the stu-1524-long-api-responses-return-error-96079-characters-exceeds branch from d6c4b3e to 5fccba7 Compare April 8, 2026 11:07
@epeicher epeicher changed the title Trim oversized plan field in wpcom_site_info response Strip bloated plan.features from wpcom_request responses Apr 8, 2026
@wpmobilebot
Copy link
Copy Markdown
Collaborator

wpmobilebot commented Apr 8, 2026

📊 Performance Test Results

Comparing b7eca66 vs trunk

app-size

Metric trunk b7eca66 Diff Change
App Size (Mac) 1261.52 MB 1261.53 MB +0.00 MB ⚪ 0.0%

site-editor

Metric trunk b7eca66 Diff Change
load 1908 ms 1927 ms +19 ms ⚪ 0.0%

site-startup

Metric trunk b7eca66 Diff Change
siteCreation 9110 ms 9132 ms +22 ms ⚪ 0.0%
siteStartup 4297 ms 4941 ms +644 ms 🔴 15.0%

Results are median values from multiple test runs.

Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff)

@epeicher epeicher changed the title Strip bloated plan.features from wpcom_request responses Trim oversized plan field in wpcom_request response Apr 8, 2026
@epeicher epeicher changed the title Trim oversized plan field in wpcom_request response Strip unnecessary fields in wpcom_request response Apr 8, 2026
List endpoints like GET /templates can return 80K+ chars of block markup.
Strip content and _links from array items when the response exceeds 80K
chars — the agent can still identify items by slug/title and fetch
individual ones for full content.
@epeicher epeicher requested review from a team and youknowriad April 8, 2026 11:49
}

// Case 1: plan.features can be 60K+ chars — keep only essential plan properties
if ( ! Array.isArray( result ) && result.plan?.features ) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me this seems too specific to a given endpoint, Is there a way to apply a generic fix instead (like overriding the token limit or telling the agent to use the minim required properties...). I don't believe we should have specifics like that because it will be hard to scale and adapt as the endpoints evolve...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point about scalability. I looked into a few alternatives:

Prompt-based: Tell the agent to always use _fields (wp/v2) or fields (v1.1) to request only what it needs. Works for most endpoints but doesn't fix the plan case. Even with fields=ID,name,description,URL,plan, the plan field alone is 63K+ because features is deeply nested and the API doesn't support sub-field filtering like fields=plan.product_slug. Plus the agent might not always follow the instruction.

Increasing the token limit: Would work but the LLM ends up processing 60K+ chars of plan.features that it never reads. The system prompt already hardcodes what each plan tier can do, so the agent only looks at product_slug and is_free. Same story with array listings where content and _links get ignored when the agent is just browsing. Feels wasteful to bump the token budget for data that gets thrown away.

On the coupling concern: I don't think these endpoint shapes will change that much. plan.features has had this structure for a long time, and content/_links are standard WP REST API fields. But I get the concern about hardcoding endpoint-specific stuff.

Proposal: Add prompt guidance so the agent uses _fields/fields by default, and keep compactResponse() as a safety net for what field filtering can't solve (mainly plan.features).

That said, if you'd rather avoid the coupling I'm also fine with just increasing the token limit and updating the prompt to use fields. What do you think?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's just one specific case, I'm fine with it if we add a good comment to explain that it's a special case and not a pattern to follow, with the fields guidance for the generic case.

Do you think the fields guidance will solve all the other cases?

Curious about @lezama's thoughts as well as he was working on alternative solutions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have applied the suggestions as part of c457f53 and tested different scenarios, and I have not found the error. The suggested changes seem to do the trick.

@lezama, the approach of trimming the output suggested here is an alternative option that can be applied on top of this changes so we ensure the error is not displayed to the user. In some testing, I have found that the limit is not exact so we can add some extra margin to prevent the error.

@youknowriad youknowriad requested a review from lezama April 8, 2026 16:19
Add system prompt hint instructing the agent to use _fields on wp/v2
listing endpoints to minimize response sizes. Scope compactResponse()
to only handle plan.features stripping with a clear comment that this
is a special case (the API doesn't support sub-field filtering). Remove
the generic array compaction in favor of prompt-driven field selection.
Copy link
Copy Markdown
Member

@sejas sejas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes sense to remove plan features if they are 60K!. I left a couple of suggestions.

* the system prompt instructs the agent to use `_fields` (wp/v2) or `fields` (v1.1)
* query params to request only the properties it needs.
*/
function compactResponse( result: ApiResponse ): ApiResponse {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should use a more specific function name, like stripPlanFeatures.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, I have renamed it as part of e21a84e

* system prompt hardcodes what each plan tier can do.
*
* This is NOT a pattern to follow for other endpoints. For general large responses,
* the system prompt instructs the agent to use `_fields` (wp/v2) or `fields` (v1.1)
Copy link
Copy Markdown
Member

@sejas sejas Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this accurate? I didn’t see the system prompt mention fields for v1.1. Should we add that information to the system prompt?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch! I have updated the system prompt as part of e21a84e as I identified that sometimes fields were failing. I have added a suggestion to use both _fields for wp/v2 or fields for v1.1 to reduce the response size. I have tested multiple scenarios and they all work fine. I have tested:

  • What's the current name, tagline, and active theme of this site?
  • Redesign my site to be more polished
  • Can you update the coming-soon template to have a light background instead of the current one?

And I have not obtained the error

Update system prompt to instruct the agent to use fields (v1.1) and
_fields (wp/v2) to minimize response sizes, always including ID for
v1.1 requests. Rename compactResponse to stripOversizedFields for
clarity.

return textResult( JSON.stringify( result, null, 2 ) );
const compacted = stripOversizedFields( result );
return textResult( JSON.stringify( compacted, null, 2 ) );
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it’s better to use JSON.stringify(result) instead of JSON.stringify(compacted, null, 2), since the added indentation increases token usage. I learned this in #3011. I think we can close that PR in favor of this one?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion @lezama! I will apply that

I learned this in #3011. I think we can close that PR in favor of this one?

I think so, and we can apply the learnings on #3011 on follow-ups if required.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @lezama, I went ahead and merged this. You'll want to merge trunk into #3005 to pick up the changes and continue from there or maybe just close it as discussed

@epeicher epeicher enabled auto-merge (squash) April 9, 2026 16:03
@epeicher epeicher merged commit 770e6ba into trunk Apr 9, 2026
8 of 10 checks passed
@epeicher epeicher deleted the stu-1524-long-api-responses-return-error-96079-characters-exceeds branch April 9, 2026 16:07
katinthehatsite pushed a commit that referenced this pull request Apr 9, 2026
* Strip bloated plan.features from wpcom_request responses

The WP.com /sites/{id} endpoint returns a plan object whose features
sub-field alone is 60K+ characters, pushing the total response past
Claude Code's ~100K character MCP tool result limit. The agent only
needs product_slug, is_free, and expired to gate features, since the
system prompt hardcodes what each plan tier can and can't do. Strip
plan.features and keep only essential plan properties.

* Also compact large array responses by stripping content and _links

List endpoints like GET /templates can return 80K+ chars of block markup.
Strip content and _links from array items when the response exceeds 80K
chars — the agent can still identify items by slug/title and fetch
individual ones for full content.

* Add _fields prompt guidance and scope plan compaction as special case

Add system prompt hint instructing the agent to use _fields on wp/v2
listing endpoints to minimize response sizes. Scope compactResponse()
to only handle plan.features stripping with a clear comment that this
is a special case (the API doesn't support sub-field filtering). Remove
the generic array compaction in favor of prompt-driven field selection.

* Add fields guidance for v1.1, rename stripOversizedFields

Update system prompt to instruct the agent to use fields (v1.1) and
_fields (wp/v2) to minimize response sizes, always including ID for
v1.1 requests. Rename compactResponse to stripOversizedFields for
clarity.

* Remove indentation in JSON to save tokens
sejas added a commit that referenced this pull request Apr 9, 2026
* [skip ci] Code freeze: Update translatable strings for 1.7.8

* [skip ci] Code freeze: Add draft release notes for 1.7.8

* Add push/pull/import/export MCP tools for AI agents (#3022)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* Sort studio code commands and subcommands alphabetically (#3027)

* Moved the `code` command registration in `apps/cli/index.ts` so that top-level CLI commands appear in alphabetical order

* Strip unnecessary fields in wpcom_request response (#3005)

* Strip bloated plan.features from wpcom_request responses

The WP.com /sites/{id} endpoint returns a plan object whose features
sub-field alone is 60K+ characters, pushing the total response past
Claude Code's ~100K character MCP tool result limit. The agent only
needs product_slug, is_free, and expired to gate features, since the
system prompt hardcodes what each plan tier can and can't do. Strip
plan.features and keep only essential plan properties.

* Also compact large array responses by stripping content and _links

List endpoints like GET /templates can return 80K+ chars of block markup.
Strip content and _links from array items when the response exceeds 80K
chars — the agent can still identify items by slug/title and fetch
individual ones for full content.

* Add _fields prompt guidance and scope plan compaction as special case

Add system prompt hint instructing the agent to use _fields on wp/v2
listing endpoints to minimize response sizes. Scope compactResponse()
to only handle plan.features stripping with a clear comment that this
is a special case (the API doesn't support sub-field filtering). Remove
the generic array compaction in favor of prompt-driven field selection.

* Add fields guidance for v1.1, rename stripOversizedFields

Update system prompt to instruct the agent to use fields (v1.1) and
_fields (wp/v2) to minimize response sizes, always including ID for
v1.1 requests. Rename compactResponse to stripOversizedFields for
clarity.

* Remove indentation in JSON to save tokens

* Fix dark mode visibility for error/success text in site list (#3034)

* Fix dark mode onbiarding screen (#3025)

Co-authored-by: Kateryna Kodonenko <kateryna@automattic.com>

* Studio: Filter out deprecated warnings from fatal errors (#3018)

* Filter out deprecated warnings from fatal errors

* Ensure our error filtering approach is consistent with CLI

* Apply changes to default exporter

* Fix unit tests

---------

Co-authored-by: Kateryna Kodonenko <kateryna@automattic.com>

* [skip ci] Update translations

* [skip ci] Bump version to 1.7.8-beta1

* CLI: ensure Studio root exists before starting code agent (#3039)

* Ensure startAiAgent() checks whether ~/Studio exists before launching the Claude SDK.

* Define a localeData type to fix lint error: The inferred type of this
node exceeds the maximum length the compiler will serialize. An explicit
type annotation is needed. (ts 7056)

* [skip ci] Bump version to 1.7.8-beta2

---------

Co-authored-by: Riad Benguella <benguella@gmail.com>
Co-authored-by: Antonio Sejas <antonio.sejas@automattic.com>
Co-authored-by: Roberto Aranda <roberto.aranda@automattic.com>
Co-authored-by: Bernardo Cotrim <bmmcotrim@gmail.com>
Co-authored-by: katinthehatsite <katerynakodonenko@gmail.com>
Co-authored-by: Kateryna Kodonenko <kateryna@automattic.com>
Co-authored-by: Jorge Costa <jorge.costa@developer.pt>
Co-authored-by: Antonio Sejas <antonio@sejas.es>
katinthehatsite added a commit that referenced this pull request Apr 10, 2026
* [skip ci] Code freeze: Update translatable strings for 1.7.8

* [skip ci] Code freeze: Add draft release notes for 1.7.8

* Add push/pull/import/export MCP tools for AI agents (#3022)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* Sort studio code commands and subcommands alphabetically (#3027)

* Moved the `code` command registration in `apps/cli/index.ts` so that top-level CLI commands appear in alphabetical order

* Strip unnecessary fields in wpcom_request response (#3005)

* Strip bloated plan.features from wpcom_request responses

The WP.com /sites/{id} endpoint returns a plan object whose features
sub-field alone is 60K+ characters, pushing the total response past
Claude Code's ~100K character MCP tool result limit. The agent only
needs product_slug, is_free, and expired to gate features, since the
system prompt hardcodes what each plan tier can and can't do. Strip
plan.features and keep only essential plan properties.

* Also compact large array responses by stripping content and _links

List endpoints like GET /templates can return 80K+ chars of block markup.
Strip content and _links from array items when the response exceeds 80K
chars — the agent can still identify items by slug/title and fetch
individual ones for full content.

* Add _fields prompt guidance and scope plan compaction as special case

Add system prompt hint instructing the agent to use _fields on wp/v2
listing endpoints to minimize response sizes. Scope compactResponse()
to only handle plan.features stripping with a clear comment that this
is a special case (the API doesn't support sub-field filtering). Remove
the generic array compaction in favor of prompt-driven field selection.

* Add fields guidance for v1.1, rename stripOversizedFields

Update system prompt to instruct the agent to use fields (v1.1) and
_fields (wp/v2) to minimize response sizes, always including ID for
v1.1 requests. Rename compactResponse to stripOversizedFields for
clarity.

* Remove indentation in JSON to save tokens

* Fix dark mode visibility for error/success text in site list (#3034)

* Fix dark mode onbiarding screen (#3025)

Co-authored-by: Kateryna Kodonenko <kateryna@automattic.com>

* Studio: Filter out deprecated warnings from fatal errors (#3018)

* Filter out deprecated warnings from fatal errors

* Ensure our error filtering approach is consistent with CLI

* Apply changes to default exporter

* Fix unit tests

---------

Co-authored-by: Kateryna Kodonenko <kateryna@automattic.com>

* [skip ci] Update translations

* [skip ci] Bump version to 1.7.8-beta1

* CLI: ensure Studio root exists before starting code agent (#3039)

* Ensure startAiAgent() checks whether ~/Studio exists before launching the Claude SDK.

* Define a localeData type to fix lint error: The inferred type of this
node exceeds the maximum length the compiler will serialize. An explicit
type annotation is needed. (ts 7056)

* [skip ci] Bump version to 1.7.8-beta2

* Update illustration colors and add dot grid background (#3004)

* Update Sync and Preview illustrations with dark mode support and dot grid background

Rebuild the Sync tab illustration SVG with proper light/dark mode color switching.
Update the Preview tab browser chrome to use light colors in light mode.
Add an interactive DotGrid canvas component behind both illustrations with a
radial gradient mask for a clean fade effect.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Extract IllustrationGrid wrapper, use CSS tokens in SVGs, add tests

- Extract shared IllustrationGrid component (DotGrid + radial mask)
  used by both Sync and Preview tabs
- Replace hardcoded SVG colors with CSS custom properties
  (--color-frame-surface, --color-frame-bg, etc.) so illustrations
  adapt automatically to theme changes
- Scope SVG class names with short prefixes (sti-, sds-) to avoid
  collisions
- Add basic tests for DotGrid and IllustrationGrid components

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Mock DotGrid in sync tests to fix canvas error in jsdom

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Respect prefers-reduced-motion in DotGrid

When reduced motion is preferred, render a static grid with no intro
animation, hover repulsion, or click ripples. Mouse event listeners
are not attached at all. The grid still responds to resize and color
scheme changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Keep WP logo white in dark mode on blue browser, dedup resize logic

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Solve for strange sidebars

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: katinthehatsite <katerynakodonenko@gmail.com>
Co-authored-by: Kateryna Kodonenko <kateryna@automattic.com>

* Upgrade archiver to v7 to fix glob and inflight deprecation warnings (#3050)

* CLI: upgrade archiver to v7 to fix glob and inflight deprecation warnings

archiver@6 → archiver@7 pulls in archiver-utils@5 which uses glob@10
instead of glob@8, eliminating the glob and inflight deprecation warnings.

@types/archiver@7 dropped followSymlinks from CoreOptions (it's still
supported at runtime), so cast ArchiverOptions at call sites instead of
patching node_modules. Also fixes the broken ProgressData named import
which doesn't work with the export= module style in @types/archiver@7.

* Studio: upgrade archiver to v7, drop @types/archiver patch

Consistent with the CLI upgrade. Drops the @types+archiver+6.0.4 patch
in favour of the same cast-based approach used in apps/cli.

* Studio: remove obsolete archiver@6 runtime patch

* Studio: Fix sync info icon color in dark mode (#3053)

The info icons next to the push progress bar had no fill color class,
defaulting to black which is invisible on the dark background. Add
fill-frame-text-secondary to match the existing offline icon style.

* Update CLI README with GIF and import/export/push/pull (#3029)

* Update CLI README

* Tweaks

* More tweaks

* Tweak

* Wider

* Enforce minimum node version in the CLI (#3049)

* Enforce minimum node version in the CLI

* Tweaks

* Allow translations to load first

* Fix sidebar top padding on Windows (#3026)

* [skip ci] Update translations

* [skip ci] Bump version to 1.7.8-beta3

---------

Co-authored-by: Riad Benguella <benguella@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Antonio Sejas <antonio.sejas@automattic.com>
Co-authored-by: Roberto Aranda <roberto.aranda@automattic.com>
Co-authored-by: Bernardo Cotrim <bmmcotrim@gmail.com>
Co-authored-by: katinthehatsite <katerynakodonenko@gmail.com>
Co-authored-by: Kateryna Kodonenko <kateryna@automattic.com>
Co-authored-by: Jorge Costa <jorge.costa@developer.pt>
Co-authored-by: Antonio Sejas <antonio@sejas.es>
Co-authored-by: Shaun Andrews <shaun@automattic.com>
Co-authored-by: Wojtek Naruniec <wojtek.naruniec@automattic.com>
Co-authored-by: Gergely Csécsey <gergely.csecsey@automattic.com>
Co-authored-by: Fredrik Rombach Ekelund <fredrik@f26d.dev>
Co-authored-by: Volodymyr Makukha <nei.css@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants